// 打卡任务管理页面
import React, { useEffect, useState, useCallback, useMemo, useRef } from 'react';
import FullCalendar from '@fullcalendar/react';
import dayGridPlugin from '@fullcalendar/daygrid';
import timeGridPlugin from '@fullcalendar/timegrid';
import interactionPlugin from '@fullcalendar/interaction';
import { format, isBefore, parse, isSameDay, startOfDay, endOfDay, isWithinInterval } from 'date-fns';
import { Form, Input, DatePicker, Button, Typography, Tree, Modal, message, Spin } from 'antd';
import type { TreeDataNode, TreeProps, FormInstance } from 'antd';
import { calendarApi, takeAddApi, takeEditApi } from '@/api/clock/index';
import zhCN from '@fullcalendar/core/locales/zh-cn';
import dayjs from 'dayjs';
import 'antd/dist/reset.css';
import styles from './index.module.css';
import { handleNumberInput, handleTextOnlyInput } from '@/components/business/index';
const { Title } = Typography;

// 核心类型定义

/**
 * 学生信息接口
 */
interface Student {
  id: number;
  username: string;
  nickname?: string;
  title?: string;
}

/**
 * 班级数据接口
 */
interface ClassData {
  id: number;
  title: string;
  children?: Student[];
}

/**
 * 学生选择组件属性
 */
interface StudentSelectionProps {
  squad: ClassData[];
  selectedStudents: string[];
  onStudentsChange: (studentIds: string[]) => void;
  form: FormInstance;
}

/**
 * 日历事件项接口
 */
interface EventItem {
  id: string;
  sourceId: string;
  title: string;
  start: string;
  end: string;
  allDay: false;
  backgroundColor: string;
  borderColor: string;
  textColor: string;
  extendedProps: {
    sourceId: string;
    displayTime: string;
    originalStart: string;
    originalEnd: string;
    desc: string;
    score: number;
    student_id: string[];
  };
}

/**
 * 原始事件数据接口
 */
interface RawEvent {
  id: number;
  score: number;
  title: string;
  desc: string;
  student_id: string | string[];
  start_time: string;
  end_time: string;
}

/**
 * API响应接口
 */
interface ApiResponse<T> {
  code: number;
  msg: string;
  data: T & { squad?: ClassData[] };
}

/**
 * 事件详情响应接口
 */
interface EventDetailResponse {
  code: number;
  msg: string;
  data: RawEvent & { teacher_id: number; createtime: number; updatetime: number };
}

// 工具函数和配置

/**
 * 禁用过去日期
 * @param current 当前日期
 * @returns 是否禁用
 */
const disabledDate = (current: dayjs.Dayjs | null) => {
  if (!current) return false;
  return current.isBefore(dayjs().startOf('day'));
};

/**
 * 时间选择器配置
 */
const showTimeConfig = {
  showTime: { hideDisabledOptions: true },
  format: 'YYYY-MM-DD HH:mm:ss',
};

/**
 * 学生选择树组件
 */
const StudentTreeSelection = React.memo(({
  squad,
  selectedStudents,
  onStudentsChange,
  form
}: StudentSelectionProps) => {
  // 状态管理
  const [localExpandedKeys, setLocalExpandedKeys] = useState<React.Key[]>([]);
  const treeRef = useRef<HTMLDivElement>(null);

  /**
   * 计算树形数据
   */
  const treeData = useMemo(() => {
    return squad.map(classData => ({
      title: classData.title,
      key: `class-${classData.id}`,
      checkable: !!(classData.children && classData.children.length),
      disableCheckbox: !(classData.children && classData.children.length),
      children: classData.children?.map(student => ({
        title: student.title || student.username,
        key: `student-${student.id}`,
        isLeaf: true
      }))
    }));
  }, [squad]);

  /**
   * 计算需要展开的班级
   */
  const getExpandedClasses = useMemo(() => {
    if (!selectedStudents.length) return [];

    return squad
      .filter(classData =>
        classData.children?.some(student =>
          selectedStudents.includes(String(student.id))
        )
      )
      .map(classData => `class-${classData.id}`);
  }, [squad, selectedStudents]);

  // 同步展开状态
  useEffect(() => {
    setLocalExpandedKeys(getExpandedClasses);
  }, [getExpandedClasses]);

  /**
   * 展开/折叠时保持滚动位置
   */
  const onExpand: TreeProps['onExpand'] = (expandedKeysValue) => {
    const scrollTop = treeRef.current?.querySelector('.ant-tree-scroll')?.scrollTop || 0;
    setLocalExpandedKeys(expandedKeysValue);

    requestAnimationFrame(() => {
      if (treeRef.current) {
        const scrollContainer = treeRef.current.querySelector('.ant-tree-scroll') as HTMLElement;
        scrollContainer?.scrollTo({ top: scrollTop, behavior: 'auto' });
      }
    });
  };

  /**
   * 勾选学生同步表单
   */
  const onCheck: TreeProps['onCheck'] = (checkedKeysValue) => {
    const studentIds = (checkedKeysValue as React.Key[])
      .filter(key => typeof key === 'string' && key.startsWith('student-'))
      .map(key => key.toString().replace('student-', ''))
      .filter(Boolean);

    onStudentsChange(studentIds);
    form.setFieldValue('selectedStudents', studentIds);
  };

  /**
   * 勾选的学生ID
   */
  const checkedKeys = useMemo(() => {
    return selectedStudents.map(id => `student-${id}`);
  }, [selectedStudents]);

  return (
    <div ref={treeRef}>
      <Tree
        checkable
        selectable={false}
        onExpand={onExpand}
        expandedKeys={localExpandedKeys}
        autoExpandParent={false} // 禁用自动展开，避免冲突
        onCheck={onCheck}
        checkedKeys={checkedKeys}
        treeData={treeData}
        height={300}
        style={{ background: 'transparent' }}
        virtual={false} // 禁用虚拟滚动，解决滚动问题
      />
    </div>
  );
}, (prevProps, nextProps) => {
  // 自定义比较函数 - 优化性能
  return (
    prevProps.squad === nextProps.squad &&
    prevProps.selectedStudents.length === nextProps.selectedStudents.length &&
    prevProps.selectedStudents.every((id, index) => id === nextProps.selectedStudents[index]) &&
    prevProps.form === nextProps.form
  );
});

/**
 * 主组件 - 打卡任务管理
 */
const ExperimentalSchedule = () => {
  // 状态管理
  const [events, setEvents] = useState<EventItem[]>([]); // 日历事件列表
  const [isModalOpen, setIsModalOpen] = useState(false); // 模态框显示状态
  const [isAddMode, setIsAddMode] = useState(false); // 是否为新增模式
  const [loading, setLoading] = useState(false); // 页面加载状态
  const [detailLoading, setDetailLoading] = useState(false); // 详情加载状态
  const today = startOfDay(new Date()); // 今天日期
  const MAX_EVENTS_PER_DAY = 4; // 每天最大事件数量
  const [form] = Form.useForm(); // 表单实例
  const [selectedStudents, setSelectedStudents] = useState<string[]>([]); // 选中的学生ID列表
  const [squad, setSquad] = useState<ClassData[]>([]); // 班级和学生数据
  const [currentEditingEvent, setCurrentEditingEvent] = useState<EventItem | null>(null); // 当前编辑的事件

  // 回调函数

  /**
   * 记忆化学生选择回调
   */
  const handleStudentsChange = useCallback((studentIds: string[]) => {
    setSelectedStudents(studentIds);
  }, []);

  /**
   * 事件颜色配置
   */
  const colorConfig = useMemo(() => [
    { backgroundColor: '#3498db', textColor: 'white' },
    { backgroundColor: '#2ecc71', textColor: 'white' },
    { backgroundColor: '#f39c12', textColor: 'white' },
    { backgroundColor: '#9b59b6', textColor: 'white' },
    { backgroundColor: '#e74c3c', textColor: 'white' },
    { backgroundColor: '#1abc9c', textColor: 'white' },
  ], []);

  /**
   * 获取事件颜色
   */
  const getEventColor = useCallback((id: string) => {
    const numericId = parseInt(id, 10) || 0;
    return colorConfig[numericId % colorConfig.length];
  }, [colorConfig]);

  /**
   * 格式化时间显示
   */
  const formatTime = useCallback((timeStr: string) => {
    try {
      return format(parse(timeStr, 'yyyy-MM-dd HH:mm:ss', new Date()), 'HH:mm');
    } catch {
      return '00:00';
    }
  }, []);

  /**
   * 处理时间格式转换
   */
  const handleTimeFormat = useCallback((startStr: string, endStr: string) => {
    try {
      const start = parse(startStr, 'yyyy-MM-dd HH:mm:ss', new Date());
      const end = parse(endStr, 'yyyy-MM-dd HH:mm:ss', new Date());
      return {
        start: format(start, "yyyy-MM-dd'T'HH:mm:ss"),
        end: format(end, "yyyy-MM-dd'T'HH:mm:ss"),
      };
    } catch {
      const now = new Date();
      return {
        start: format(now, "yyyy-MM-dd'T'HH:mm:ss"),
        end: format(now, "yyyy-MM-dd'T'HH:mm:ss"),
      };
    }
  }, []);

  /**
   * 处理学生ID格式
   */
  const processStudentIds = useCallback((student_id: string | string[]): string[] => {
    if (typeof student_id === 'string') {
      return student_id.split(',').filter(Boolean);
    }
    return student_id?.filter(id => String(id).trim()).map(String) || [];
  }, []);

  /**
   * 获取日历数据
   */
  const fetchCalendarData = useCallback(async () => {
    try {
      setLoading(true);
      const response = await calendarApi().signIn({ user_id: 459, role: 1 }) as ApiResponse<{ list: RawEvent[] }>;

      if (!response?.code === 1 || !response.data) {
        throw new Error('数据获取失败');
      }

      const { list, squad } = response.data;
      const formatEvents: EventItem[] = list.map(item => {
        const { start, end } = handleTimeFormat(item.start_time, item.end_time);
        const { backgroundColor, textColor, borderColor = backgroundColor } = getEventColor(String(item.id));
        return {
          id: String(item.id),
          sourceId: String(item.id),
          title: item.title || '未命名任务',
          start,
          end,
          allDay: false,
          backgroundColor,
          borderColor,
          textColor,
          extendedProps: {
            sourceId: String(item.id),
            displayTime: formatTime(item.start_time),
            originalStart: item.start_time,
            originalEnd: item.end_time,
            desc: item.desc || '',
            score: item.score || 0,
            student_id: processStudentIds(item.student_id)
          }
        };
      });

      setEvents(formatEvents);
      setSquad(squad || []);
    } catch (error) {
      message.error('获取打卡任务数据失败');
      setEvents([]);
      setSquad([]);
    } finally {
      setLoading(false);
    }
  }, [handleTimeFormat, getEventColor, formatTime, processStudentIds]);

  // 初始化加载数据
  useEffect(() => {
    fetchCalendarData();
  }, [fetchCalendarData]);

  /**
   * 计算日期事件数量
   */
  const countEventsOnDate = useCallback((targetDate: Date) => {
    const targetDayStart = startOfDay(targetDate);
    const targetDayEnd = endOfDay(targetDate);

    return events.filter(event => {
      try {
        const eventStart = parse(event.start, "yyyy-MM-dd'T'HH:mm:ss", new Date());
        const eventEnd = parse(event.end, "yyyy-MM-dd'T'HH:mm:ss", new Date());

        return (
          isSameDay(eventStart, targetDate) ||
          isSameDay(eventEnd, targetDate) ||
          (isBefore(eventStart, targetDayStart) && isBefore(targetDayEnd, eventEnd)) ||
          isWithinInterval(targetDayStart, { start: eventStart, end: eventEnd }) ||
          isWithinInterval(targetDayEnd, { start: eventStart, end: eventEnd })
        );
      } catch {
        return false;
      }
    }).length;
  }, [events]);

  /**
   * 提取事件ID
   */
  const extractEventId = useCallback((event: EventItem): string | null => {
    return event.extendedProps?.sourceId || event.id || null;
  }, []);

  /**
   * 点击事件编辑
   */
  const handleEventClick = useCallback(async (clickInfo: any) => {
    setIsAddMode(false);
    setIsModalOpen(true);
    const event = clickInfo.event;
    setCurrentEditingEvent(event);

    try {
      setDetailLoading(true);
      const eventId = extractEventId(event);
      if (!eventId || isNaN(Number(eventId))) {
        throw new Error('无效的事件ID');
      }

      const response = await takeEditApi().signIn({
        id: Number(eventId),
        user_id: 459,
        role: 1
      }) as EventDetailResponse;

      if (!response?.code === 1 || !response.data) {
        throw new Error('详情获取失败');
      }

      const eventDetail = response.data;
      const studentIds = processStudentIds(eventDetail.student_id);
      await form.setFieldsValue({
        title: eventDetail.title?.trim() || '',
        desc: eventDetail.desc?.trim() || '',
        score: eventDetail.score ? String(eventDetail.score) : '',
        startTime: dayjs(eventDetail.start_time),
        endTime: dayjs(eventDetail.end_time),
        selectedStudents: studentIds
      });
      setSelectedStudents(studentIds);
    } catch (error) {
      message.error('获取事件详情失败，请重试');
      setIsModalOpen(false);
    } finally {
      setDetailLoading(false);
    }
  }, [form, extractEventId, processStudentIds]);

  /**
   * 选择日期新建事件
   */
  const handleSelect = useCallback((selectInfo: any) => {
    try {
      const selectedDate = startOfDay(selectInfo.start);
      if (isBefore(selectedDate, today)) {
        message.warning('不能选择比今天更早的日期添加事件');
        return;
      }
      if (countEventsOnDate(selectedDate) >= MAX_EVENTS_PER_DAY) {
        message.warning(`每天最多只能添加 ${MAX_EVENTS_PER_DAY} 个事件`);
        return;
      }
      form.resetFields();
      setIsAddMode(true);
      setIsModalOpen(true);
      setSelectedStudents([]);
      setCurrentEditingEvent(null);
    } catch (error) {
      message.error('打开新增窗口失败，请重试');
    } finally {
      selectInfo.view.calendar.unselect();
    }
  }, [form, today, countEventsOnDate, MAX_EVENTS_PER_DAY]);

  /**
   * 取消操作
   */
  const handleCancel = useCallback(() => {
    setIsModalOpen(false);
    form.resetFields();
    setSelectedStudents([]);
    setCurrentEditingEvent(null);
  }, [form]);

  /**
   * 渲染事件内容
   */
  const renderEventContent = useCallback((eventInfo: any) => {
    return (
      <div
        className={styles.eventContent}
        style={{
          background: eventInfo.event.backgroundColor,
          color: eventInfo.event.textColor,
        }}
      >
        <span className={styles.eventTime}>
          {eventInfo.event.extendedProps?.displayTime || ''}
        </span>
        <span className={styles.eventTitle}>{eventInfo.event.title}</span>
      </div>
    );
  }, []);

  /**
   * 提交表单
   */
  const handleSubmit = useCallback(async (values: any) => {
    try {
      setLoading(true);
      const submitData = {
        title: values.title.trim(),
        desc: values.desc.trim(),
        score: Number(values.score),
        start_time: values.startTime.format('YYYY-MM-DD HH:mm:ss'),
        end_time: values.endTime.format('YYYY-MM-DD HH:mm:ss'),
        user_id: 459,
        role: 1,
        student_id: values.selectedStudents.join(',')
      };

      if (!isAddMode && currentEditingEvent) {
        const eventId = extractEventId(currentEditingEvent);
        if (!eventId || isNaN(Number(eventId))) {
          throw new Error('无效的事件ID');
        }
        (submitData as any).id = Number(eventId);
      }

      const response = await takeAddApi().signIn(submitData);
      if (response?.data?.code === 1) {
        message.success(isAddMode ? '任务创建成功' : '任务编辑成功');
        handleCancel();
        fetchCalendarData();
      } else {
        message.error(response?.data?.msg || '操作失败');
      }
    } catch (error) {
      message.error(isAddMode ? '任务创建失败' : '任务编辑失败');
    } finally {
      setLoading(false);
    }
  }, [isAddMode, currentEditingEvent, extractEventId, handleCancel, fetchCalendarData]);

  return (
    <div className={styles.container}>
      <Title level={4} className={styles.pageTitle}>打卡任务</Title>

      {/* 日历组件 */}
      <Spin spinning={loading} tip="加载中...">
        <FullCalendar
          plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]}
          initialView="dayGridMonth"
          headerToolbar={{ left: "prev", center: "title", right: "today,next" }}
          locale={zhCN}
          buttonText={{ today: '今天' }}
          allDayText="全天"
          firstDay={1}
          slotLabelFormat={{ hour: '2-digit', minute: '2-digit', meridiem: false, hour12: false }}
          height="auto"
          aspectRatio={1.2}
          events={events}
          eventClick={handleEventClick}
          select={handleSelect}
          selectable={true}
          editable={true}
          eventDurationEditable={true}
          dayMaxEvents={true}
          dayMaxEventRows={3}
          slotMinTime="00:00:00"
          slotMaxTime="24:00:00"
          eventContent={renderEventContent}
        />
      </Spin>

      {/* 新增/编辑任务模态框 */}
      <Modal
        title={isAddMode ? '新建任务' : '编辑任务'}
        open={isModalOpen}
        onCancel={handleCancel}
        footer={[
          <Button key="cancel" onClick={handleCancel}>关闭</Button>,
          <Button key="submit" type="primary" htmlType="submit" form="taskForm" loading={loading || detailLoading}>
            {isAddMode ? '新建' : '保存'}
          </Button>,
        ]}
        width={550}
        maskClosable={false}
        centered
        styles={{
          body: {
            height: '500px', // 设置固定高度
            overflowY: 'auto', // 启用垂直滚动
            padding: '16px 24px'
          }
        }}
      >
        <Spin spinning={detailLoading} tip="加载事件详情...">
          <Form
            id="taskForm"
            form={form}
            layout="horizontal"
            labelCol={{ span: 4 }}
            labelAlign="left"
            wrapperCol={{ span: 20 }}
            onFinish={handleSubmit}
            initialValues={{ selectedStudents: [] }}
          >
            {/* 任务标题表单项 */}
            <Form.Item
              name="title"
              label="任务标题"
              rules={[
                { required: true, message: '请输入任务标题' },
                { max: 10, message: '标题长度不能超过10个字符' }
              ]}
            >
              <Input
                placeholder="请输入任务标题"
                maxLength={10}
                onInput={(e: React.ChangeEvent<HTMLInputElement>) =>
                  handleTextOnlyInput(form, 'title', e, { maxLength: 10 })
                }
                onBlur={(e: React.FocusEvent<HTMLInputElement>) =>
                  handleTextOnlyInput(form, 'title', e as any, { maxLength: 10 })
                }
              />
            </Form.Item>

            {/* 任务介绍表单项 */}
            <Form.Item
              name="desc"
              label="任务介绍"
              rules={[{ required: true, message: '请输入任务介绍' }, { max: 20, message: '介绍长度不能超过20个字符' }]}
            >
              <Input
                placeholder="请输入任务介绍"
                maxLength={20}
                onInput={(e: React.ChangeEvent<HTMLInputElement>) =>
                  handleTextOnlyInput(form, 'desc', e, { maxLength: 20 })
                }
                onBlur={(e: React.FocusEvent<HTMLInputElement>) =>
                  handleTextOnlyInput(form, 'desc', e as any, { maxLength: 20 })
                }
              />
            </Form.Item>

            {/* 积分奖励表单项 */}
            <Form.Item
              name="score"
              label="积分奖励"
              rules={[
                { required: true, message: '请输入积分奖励' },
                {
                  validator: (_, value) => {
                    if (!value) return Promise.resolve();
                    // 直接判断值
                    if (value <= 0) {
                      return Promise.reject(new Error('积分奖励不能小于等于0'));
                    }
                    return Promise.resolve();
                  }
                }
              ]}
            >
              <Input
                placeholder="请输入积分奖励"
                onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
                  handleNumberInput(form, 'score', e, { supportDecimal: false })
                }
                onInput={(e: React.ChangeEvent<HTMLInputElement>) =>
                  handleNumberInput(form, 'score', e, { supportDecimal: false })
                }
              />
            </Form.Item>

            {/* 开始时间表单项 */}
            <Form.Item
              name="startTime"
              label="开始时间"
              rules={[
                { required: true, message: '请选择开始时间' },
                ({ getFieldValue }) => ({
                  validator(_, value) {
                    if (!value) return Promise.resolve();
                    if (value.isBefore(dayjs().startOf('day'))) {
                      return Promise.reject(new Error('开始时间不能早于今天'));
                    }
                    return Promise.resolve();
                  },
                }),
              ]}
            >
              <DatePicker {...showTimeConfig} disabledDate={disabledDate} style={{ width: '100%' }} placeholder="选择开始时间" />
            </Form.Item>

            {/* 结束时间表单项 */}
            <Form.Item
              name="endTime"
              label="结束时间"
              rules={[
                { required: true, message: '请选择结束时间' },
                ({ getFieldValue }) => ({
                  validator(_, value) {
                    if (!value) return Promise.resolve();
                    const startTime = getFieldValue('startTime');
                    if (startTime && value.isBefore(startTime)) {
                      return Promise.reject(new Error('结束时间不能早于开始时间'));
                    }
                    if (value.isBefore(dayjs().startOf('day'))) {
                      return Promise.reject(new Error('结束时间不能早于今天'));
                    }
                    return Promise.resolve();
                  },
                }),
              ]}
            >
              <DatePicker {...showTimeConfig} disabledDate={disabledDate} style={{ width: '100%' }} placeholder="选择结束时间" />
            </Form.Item>

            {/* 学生选择表单项 */}
            <Form.Item
              name="selectedStudents"
              label="学生"
              rules={[{ required: true, message: '请至少选择一名学生' }]}
            >
              <StudentTreeSelection
                squad={squad}
                selectedStudents={selectedStudents}
                onStudentsChange={handleStudentsChange}
                form={form}
              />
            </Form.Item>
          </Form>
        </Spin>
      </Modal>
    </div>
  );
};

export default ExperimentalSchedule;